﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Plumbing;
using YArchitech.Revit;

namespace YArchitech.HVAC
{
	public class PipeInsulationCalc
	{
		public double MediumTemp { get; set; }

		public double DesignTemp { get; set; }

		public double DewingTemp { get; set; }

		public InsulationLayerParam InsulationMaterial { get; set; }

		public PipeInsulationCalc(InsulationLayerParam insulationParam, double mediumTemp, double designTemp, double dewingTemp)
		{
			this.InsulationMaterial = insulationParam;
			this.MediumTemp = mediumTemp;
			this.DesignTemp = designTemp;
			this.DewingTemp = dewingTemp;
		}

		public Dictionary<Pipe, double> CalcThickness(IList<Pipe> allPipes, int calcTypeNum)
		{
			Dictionary<Pipe, double> dictionary = new Dictionary<Pipe, double>();
			foreach (Pipe pipe in allPipes)
			{
				double value = 0.0;
				if (calcTypeNum != 1)
				{
					if (calcTypeNum == 2)
					{
						value = this.GetPreventDewingThickness(pipe);
					}
				}
				else
				{
					value = this.GetKeepWarmThickness(pipe);
				}
				dictionary.Add(pipe, value);
			}
			return dictionary;
		}

		public double GetKeepWarmThickness(Pipe pipe)
		{
			this.GetPipeSegmentInfo(pipe);
			double insulationOutDia;
			if (this.pipeSegmentName.ToLower().Contains("ppr") || this.pipeSegmentName.ToLower().Contains("upvc") || this.pipeSegmentName.ToLower().Contains("pe"))
			{
				double pipeSurfaceTemp = this.CalcPipeSurfaceTemp(11.63);
				double surfaceTemp = this.CalcInsulationSurfaceTemp(pipeSurfaceTemp);
				double coeficient = this.CalcHeatCoefficient(surfaceTemp, pipeSurfaceTemp);
				insulationOutDia = this.CalcKeepWarmOutDiameter(coeficient, pipeSurfaceTemp);
			}
			else
			{
				double surfaceTemp = this.CalcInsulationSurfaceTemp(this.MediumTemp);
				double coeficient = this.CalcHeatCoefficient(surfaceTemp, this.MediumTemp);
				insulationOutDia = this.CalcKeepWarmOutDiameter(coeficient, this.MediumTemp);
			}
			return this.GetThickness(this.pipeOutDiameter, insulationOutDia);
		}

		public double GetPreventDewingThickness(Pipe pipe)
		{
			this.GetPipeSegmentInfo(pipe);
			double designTemp = this.DesignTemp;
			double insulationOutDia;
			if (this.pipeSegmentName.ToLower().Contains("ppr") || this.pipeSegmentName.ToLower().Contains("upvc"))
			{
				double pipeSurfaceTemp = this.CalcPipeSurfaceTemp(8.141);
				double baseNum = this.CalcDesignBaseNum(pipeSurfaceTemp);
				double coeficient = this.CalcHeatCoefficient(designTemp, pipeSurfaceTemp);
				insulationOutDia = this.CalcPreventDewingDiameter(coeficient, baseNum);
			}
			else
			{
				double baseNum = this.CalcDesignBaseNum(this.MediumTemp);
				double coeficient = this.CalcHeatCoefficient(designTemp, this.MediumTemp);
				insulationOutDia = this.CalcPreventDewingDiameter(coeficient, baseNum);
			}
			return this.GetThickness(this.pipeOutDiameter, insulationOutDia);
		}

		private double CalcInsulationSurfaceTemp(double pipeSurfaceTemp)
		{
			return this.GetMaxHeatLoss(pipeSurfaceTemp) / 11.63 + this.DesignTemp;
		}

		private double CalcPipeSurfaceTemp(double conductionNum)
		{
			double num = 0.24;
			if (this.pipeSegmentName.ToLower().Contains("upvc"))
			{
				num = 0.29;
			}
			double num2 = conductionNum * (this.pipeOutDiameter / (2.0 * num) * Math.Log(this.pipeOutDiameter / this.pipeInnerDiameter) + 1.0 / conductionNum);
			return (this.MediumTemp - this.DesignTemp) / num2 + this.DesignTemp;
		}

		private double CalcHeatCoefficient(double surfaceTemp, double pipeSurfaceTemp)
		{
			double result = 0.0;
			try
			{
				double num = Convert.ToDouble(this.InsulationMaterial.CoefficientNum1);
				double num2 = Convert.ToDouble(this.InsulationMaterial.CoefficientNum2);
				result = num + num2 * (pipeSurfaceTemp + surfaceTemp) / 2.0;
			}
			catch (Exception ex)
			{
				ex.Message.ToString();
				throw;
			}
			return result;
		}

		private double CalcKeepWarmOutDiameter(double coeficient, double pipeSurfaceTemp)
		{
			double constNum = 2.0 * coeficient * ((pipeSurfaceTemp - this.DesignTemp) / 0.8 / this.GetMaxHeatLoss(pipeSurfaceTemp) - 0.085984522785898534);
			return this.FittingFunction(constNum);
		}

		private double CalcPreventDewingDiameter(double coeficient, double baseNum)
		{
			double constNum = 2.0 * coeficient / 8.141 * baseNum;
			return this.FittingFunction(constNum);
		}

		private double CalcDesignBaseNum(double pipeSurfaceTemp)
		{
			return (this.DewingTemp - pipeSurfaceTemp) / (this.DesignTemp - this.DewingTemp);
		}

		private double FittingFunction(double constNum)
		{
			double num = this.pipeOutDiameter;
			double num2 = 0.0001;
			double num3;
			do
			{
				num += num2;
				num3 = constNum - num * Math.Log(num / this.pipeOutDiameter);
			}
			while (num3 > num2);
			return num;
		}

		private double GetThickness(double pipeOutDia, double insulationOutDia)
		{
			double num = (insulationOutDia - pipeOutDia) / 2.0;
			num *= 1000.0;
			double num2 = num / 5.0;
			double num3 = Math.Truncate(num2);
			num = 5.0 * num3;
			if (num2 - num3 > 0.0)
			{
				num += 5.0;
			}
			return num;
		}

		private void GetPipeSegmentInfo(Pipe pipe)
		{
			ElementId elementId = pipe.GetParameter(BuiltInParameter.RBS_PIPE_SEGMENT_PARAM).AsElementId();
			PipeSegment pipeSegment = pipe.Document.GetElementById(elementId) as PipeSegment;
			this.pipeSegmentName = pipeSegment.Name;
			IEnumerable<MEPSize> sizes = pipeSegment.GetSizes();
			double num = pipe.GetParameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM).AsDouble();
			foreach (MEPSize mepsize in sizes)
			{
				if (Math.Abs(mepsize.NominalDiameter - num) < 0.0032808398950131233)
				{
					this.pipeInnerDiameter = mepsize.InnerDiameter * 304.8 / 1000.0;
					this.pipeOutDiameter = mepsize.OuterDiameter * 304.8 / 1000.0;
					break;
				}
			}
		}

		private double GetMaxHeatLoss(double temp)
		{
			double result = 50.0;
			if (temp >= 49.9 && temp <= 50.1)
			{
				result = 58.0;
			}
			else if (temp > 50.1 && temp < 59.9)
			{
				result = this.GetHeatLossByTwoDiff(temp, 50.0, 58.0, 60.0, 65.0);
			}
			else if (temp >= 59.9 && temp <= 60.1)
			{
				result = 65.0;
			}
			else if (temp > 60.1 && temp < 99.9)
			{
				result = this.GetHeatLossByTwoDiff(temp, 60.0, 65.0, 100.0, 93.0);
			}
			else if (temp >= 99.9 && temp <= 100.1)
			{
				result = 93.0;
			}
			else if (temp > 100.1 && temp < 149.9)
			{
				result = this.GetHeatLossByTwoDiff(temp, 100.0, 93.0, 150.0, 116.0);
			}
			else if (temp >= 149.9 && temp <= 150.0)
			{
				result = 116.0;
			}
			return result;
		}

		private double GetHeatLossByTwoDiff(double calcTemp, double minTemp, double minHeat, double maxTemp, double maxHeat)
		{
			return (maxHeat * (calcTemp - minTemp) + minHeat * (maxTemp - calcTemp)) * 1.0 / (maxTemp - minTemp);
		}

		private const double AS = 11.63;

		private const double PPRλ = 0.24;

		private const double UPVCλ = 0.29;

		private const double AD = 8.141;

		private const double KD = 1.0;

		private const double KD1 = 1.4;

		private const double KD2 = 1.1;

		private double pipeInnerDiameter;

		private double pipeOutDiameter;

		private string pipeSegmentName = "";
	}
}
